using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Sdk;
using System.Diagnostics;
using Microsoft.Crm.SdkTypeProxy;

namespace Infusion.CRM.WF.CRM40ShareStep
{

    /// <summary>
    /// Share a record with specified users/teams.
    /// </summary>
    [CrmWorkflowActivity("Share Record", "Utilities")]
    public class ShareRecordActivity : SequenceActivityBase
    {

        #region Workflow Parameters

        /// <summary>
        /// Teams to share with.
        /// </summary> 
        public static DependencyProperty Team1Property = DependencyProperty.Register("Team1", typeof(Lookup), typeof(ShareRecordActivity));
        [CrmInput("Share Team 1")]
        [CrmReferenceTarget("team")]
        public Lookup Team1
        {
            get
            {
                return (Lookup)base.GetValue(Team1Property);
            }
            set
            {
                base.SetValue(Team1Property, value);
            }
        }

        public static DependencyProperty Team2Property = DependencyProperty.Register("Team2", typeof(Lookup), typeof(ShareRecordActivity));
        [CrmInput("Share Team 2")]
        [CrmReferenceTarget("team")]
        public Lookup Team2
        {
            get
            {
                return (Lookup)base.GetValue(Team2Property);
            }
            set
            {
                base.SetValue(Team2Property, value);
            }
        }

        /// <summary>
        /// Users to share with.
        /// </summary> 
        public static DependencyProperty User1Property = DependencyProperty.Register("User1", typeof(Lookup), typeof(ShareRecordActivity));
        [CrmInput("Share User 1")]
        [CrmReferenceTarget("systemuser")]
        public Lookup User1
        {
            get
            {
                return (Lookup)base.GetValue(User1Property);
            }
            set
            {
                base.SetValue(User1Property, value);
            }
        }

        public static DependencyProperty User2Property = DependencyProperty.Register("User2", typeof(Lookup), typeof(ShareRecordActivity));
        [CrmInput("Share User 2")]
        [CrmReferenceTarget("systemuser")]
        public Lookup User2
        {
            get
            {
                return (Lookup)base.GetValue(User2Property);
            }
            set
            {
                base.SetValue(User2Property, value);
            }
        }

        /// <summary>
        /// Input parameter: if true remove all shares before sharing the record.
        /// </summary>
        public static DependencyProperty RemoveSharesProperty = DependencyProperty.Register("RemoveShares", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Remove All Shares")]
        [CrmDefault("False")]
        public CrmBoolean RemoveShares
        {
            get
            {
                return (CrmBoolean)base.GetValue(RemoveSharesProperty);
            }
            set
            {
                base.SetValue(RemoveSharesProperty, value);
            }
        }

        /// <summary>
        /// Input parameter: Share Read privilege.
        /// </summary>
        public static DependencyProperty ShareReadProperty = DependencyProperty.Register("ShareRead", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Read Permission")]
        [CrmDefault("True")]
        public CrmBoolean ShareRead
        {
            get
            {
                return (CrmBoolean)base.GetValue(ShareReadProperty);
            }
            set
            {
                base.SetValue(ShareReadProperty, value);
            }
        }

        /// <summary>
        /// Input parameter: Share Write privilege.
        /// </summary>
        public static DependencyProperty ShareWriteProperty = DependencyProperty.Register("ShareWrite", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Write Permission")]
        [CrmDefault("False")]
        public CrmBoolean ShareWrite
        {
            get
            {
                return (CrmBoolean)base.GetValue(ShareWriteProperty);
            }
            set
            {
                base.SetValue(ShareWriteProperty, value);
            }
        }

        /// <summary>
        /// Input parameter: Share Delete privilege.
        /// </summary>
        public static DependencyProperty ShareDeleteProperty = DependencyProperty.Register("ShareDelete", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Delete Permission")]
        [CrmDefault("False")]
        public CrmBoolean ShareDelete
        {
            get
            {
                return (CrmBoolean)base.GetValue(ShareDeleteProperty);
            }
            set
            {
                base.SetValue(ShareDeleteProperty, value);
            }
        }

        /// <summary>
        /// Input parameter: Share Append privilege.
        /// </summary>
        public static DependencyProperty ShareAppendProperty = DependencyProperty.Register("ShareAppend", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Append Permission")]
        [CrmDefault("False")]
        public CrmBoolean ShareAppend
        {
            get
            {
                return (CrmBoolean)base.GetValue(ShareAppendProperty);
            }
            set
            {
                base.SetValue(ShareAppendProperty, value);
            }
        }

        /// <summary>
        /// Input parameter: Share AppendTo privilege.
        /// </summary>
        public static DependencyProperty ShareAppendToProperty = DependencyProperty.Register("ShareAppendTo", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Append To Permission")]
        [CrmDefault("False")]
        public CrmBoolean ShareAppendTo
        {
            get
            {
                return (CrmBoolean)base.GetValue(ShareAppendToProperty);
            }
            set
            {
                base.SetValue(ShareAppendToProperty, value);
            }
        }

        /// <summary>
        /// Input parameter: Share Assign privilege.
        /// </summary>
        public static DependencyProperty ShareAssignProperty = DependencyProperty.Register("ShareAssign", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Assign Permission")]
        [CrmDefault("False")]
        public CrmBoolean ShareAssign
        {
            get
            {
                return (CrmBoolean)base.GetValue(ShareAssignProperty);
            }
            set
            {
                base.SetValue(ShareAssignProperty, value);
            }
        }

        /// <summary>
        /// Input parameter: Share Share privilege.
        /// </summary>
        public static DependencyProperty ShareShareProperty = DependencyProperty.Register("ShareShare", typeof(CrmBoolean), typeof(ShareRecordActivity));
        [CrmInput("Share Permission")]
        [CrmDefault("False")]
        public CrmBoolean ShareShare
        {
            get
            {
                return (CrmBoolean)base.GetValue(ShareShareProperty);
            }
            set
            {
                base.SetValue(ShareShareProperty, value);
            }
        }

        /// <summary>
        /// Output parameter: Operation Result
        /// </summary> 
        public static DependencyProperty ResultProperty = DependencyProperty.Register("Result", typeof(string), typeof(ShareRecordActivity));
        [CrmOutput("Result")]
        public override string Result
        {
            get
            {
                return (string)base.GetValue(ResultProperty);
            }
            set
            {
                base.SetValue(ResultProperty, value);
            }
        }

        #endregion

        #region SequenceActivity

        protected override string ExecuteBody(Context context)
        {
            PrincipalAccess[] principals = GetPrincipals(context);

            if (this.RemoveShares.Value)
            {
                RemovePrincipals(context, principals);
            }

            AddPrincipals(context);

            return SequenceActivityBase.RESULT_SUCCESS;
        }

        #endregion

        #region Local Methods

        private PrincipalAccess[] GetPrincipals(Context context)
        {
            TargetOwnedDynamic target = new TargetOwnedDynamic();
            target.EntityName = context.CurrentEntityName;
            target.EntityId = context.CurrentRecordId;

            RetrieveSharedPrincipalsAndAccessRequest retrieve = new RetrieveSharedPrincipalsAndAccessRequest();
            retrieve.Target = target;
            RetrieveSharedPrincipalsAndAccessResponse retrieved = (RetrieveSharedPrincipalsAndAccessResponse)context.SvcHandle.Execute(retrieve);

            return retrieved.PrincipalAccesses;
        }

        private void RemovePrincipals(Context context, PrincipalAccess[] principals)
        {
            TargetOwnedDynamic target = new TargetOwnedDynamic();
            target.EntityName = context.CurrentEntityName;
            target.EntityId = context.CurrentRecordId;

            RevokeAccessRequest request = new RevokeAccessRequest();
            request.Target = target;
            foreach (PrincipalAccess principal in principals)
            {
                request.Revokee = principal.Principal;
                RevokeAccessResponse response = (RevokeAccessResponse)context.SvcHandle.Execute(request);
            }
        }

        private void AddPrincipals(Context context)
        {
            List<SecurityPrincipal> principals = new List<SecurityPrincipal>();

            if (User1 != null)
            {
                SecurityPrincipal principal = new SecurityPrincipal();
                principal.Type = SecurityPrincipalType.User;
                principal.PrincipalId = User1.Value;
                principals.Add(principal);
            }

            if (User2 != null)
            {
                SecurityPrincipal principal = new SecurityPrincipal();
                principal.Type = SecurityPrincipalType.User;
                principal.PrincipalId = User2.Value;
                principals.Add(principal);
            }

            if (Team1 != null)
            {
                SecurityPrincipal principal = new SecurityPrincipal();
                principal.Type = SecurityPrincipalType.Team;
                principal.PrincipalId = Team1.Value;
                principals.Add(principal);
            }

            if (Team2 != null)
            {
                SecurityPrincipal principal = new SecurityPrincipal();
                principal.Type = SecurityPrincipalType.Team;
                principal.PrincipalId = Team2.Value;
                principals.Add(principal);
            }

            if (principals.Count > 0)
            {
                UInt32 mask = 0;
                if (ShareAppend.Value)
                {
                    mask |= (UInt32)AccessRights.AppendAccess;
                }
                if (ShareAppendTo.Value)
                {
                    mask |= (UInt32)AccessRights.AppendToAccess;
                }
                if (ShareAssign.Value)
                {
                    mask |= (UInt32)AccessRights.AssignAccess;
                }
                if (ShareDelete.Value)
                {
                    mask |= (UInt32)AccessRights.DeleteAccess;
                }
                if (ShareRead.Value)
                {
                    mask |= (UInt32)AccessRights.ReadAccess;
                }
                if (ShareShare.Value)
                {
                    mask |= (UInt32)AccessRights.ShareAccess;
                }
                if (ShareWrite.Value)
                {
                    mask |= (UInt32)AccessRights.WriteAccess;
                }

                if (mask != 0)
                {
                    TargetOwnedDynamic target = new TargetOwnedDynamic();
                    target.EntityName = context.CurrentEntityName;
                    target.EntityId = context.CurrentRecordId;

                    GrantAccessRequest request = new GrantAccessRequest();
                    request.Target = target;

                    request.PrincipalAccess = new PrincipalAccess();
                    request.PrincipalAccess.AccessMask = (AccessRights)mask;

                    foreach (SecurityPrincipal principal in principals)
                    {
                        request.PrincipalAccess.Principal = principal;
                        GrantAccessResponse response = (GrantAccessResponse)context.SvcHandle.Execute(request);
                    }
                }
            }
        }

        #endregion

    }
}
